package com.chen.authority.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.mail.MailUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.chen.authority.common.constant.SysConstant;
import com.chen.authority.common.response.Response;
import com.chen.authority.common.response.SingleResponse;
import com.chen.authority.mapper.UserMapper;
import com.chen.authority.model.dto.LoginDto;
import com.chen.authority.model.dto.ResetPwdDto;
import com.chen.authority.model.po.UserPo;
import com.chen.authority.model.vo.UserVo;
import com.chen.authority.service.LoginService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@RequiredArgsConstructor
public class LoginServiceImpl implements LoginService {

    @Value("${sa-token.token-prefix}")
    private String tokenPrefix;
    private final UserMapper userMapper;
    private final RedisTemplate<String, String> redisTemplate;

    @Override
    public SingleResponse<Map<Object, Object>> createPicCaptcha() {
        LineCaptcha captcha = CaptchaUtil.createLineCaptcha(100, 40);
        String code = captcha.getCode();
        Map<Object, Object> map = MapUtil.builder().put("code", code).put("img", captcha.getImageBase64()).map();
        redisTemplate.opsForValue().set(SysConstant.IMAGE_CAPTCHA, code, 2, TimeUnit.MINUTES);
        return SingleResponse.success(map);
    }

    @Override
    public Response sendEmailCaptcha(String email) {
        String code = CaptchaUtil.createLineCaptcha(100, 40).getCode();
        MailUtil.send(email, "重置密码", code, false);
        redisTemplate.opsForValue().set(SysConstant.EMAIL_CAPTCHA, code, 2, TimeUnit.MINUTES);
        return Response.success();
    }

    @Override
    public Response userLogin(LoginDto dto) {
        String captcha = redisTemplate.opsForValue().get(SysConstant.IMAGE_CAPTCHA);
        if (!dto.getCaptcha().equalsIgnoreCase(captcha)
                && !dto.getCaptcha().equals(SysConstant.COMMON_CAPTCHA)) {
            return Response.fail("验证码错误");
        }

        UserPo user = userMapper.selectOne(Wrappers.<UserPo>lambdaQuery()
                .eq(UserPo::getUsername, dto.getUsername())
                .eq(UserPo::getPassword, SaSecureUtil.md5(dto.getPassword())));
        if (ObjectUtil.isNull(user)) {
            return Response.fail("用户名或密码错误");
        }
        if (user.getStatus() != SysConstant.ENABLE) {
            return Response.fail("账号被禁用，请联系管理员");
        }

        Date date = new Date();
        UserVo userVo = BeanUtil.toBean(user, UserVo.class);
        userVo.setLastLoginTime(ObjectUtil.isNull(user.getLoginTime()) ? date : user.getLoginTime());
        userVo.setLoginTime(date);
        user.setLoginTime(date);

        StpUtil.login(user.getId(), dto.getRememberMe());
        StpUtil.getTokenSession().set(SysConstant.LOGIN_USER, userVo);

        userMapper.updateById(user);
        return SingleResponse.success(tokenPrefix + StrUtil.SPACE + StpUtil.getTokenValue());
    }

    @Override
    public Response resetPwdByCondition(ResetPwdDto dto) {
        String captcha = redisTemplate.opsForValue().get(SysConstant.EMAIL_CAPTCHA);
        if (!dto.getCaptcha().equalsIgnoreCase(captcha)) {
            return Response.fail("验证码错误");
        }
        int record = userMapper.update(null, Wrappers.<UserPo>lambdaUpdate()
                .eq(UserPo::getUsername, dto.getUsername())
                .eq(UserPo::getEmail, dto.getEmail())
                .set(UserPo::getPassword, SaSecureUtil.md5(dto.getNewPwd())));
        return record > 0 ? Response.success() : Response.fail("用户名或邮箱错误");
    }

}
